﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace RoketPack.Management.Objects
{
    class File : Object
    {
        private string p_Local = null;
        private string p_Remote = null;
        private bool p_Generated = false;
        private byte[] m_Data = null;

        internal File(string local, string remote, bool generated)
        {
            this.p_Local = local;
            this.p_Remote = remote;
            this.p_Generated = generated;
        }

        internal string Local
        {
            get
            {
                return this.p_Local;
            }
        }

        internal string Remote
        {
            get
            {
                return this.p_Remote;
            }
        }

        internal bool Generated
        {
            get
            {
                return this.p_Generated;
            }
        }

        internal override bool Download(Installation installation, Manager.VoidLambdaDouble progressevent)
        {
            if (installation.Mode == Installation.InstallMode.INSTALL)
            {
                this.m_Data = Downloader.Grab(PathTranslator.Parse(this.p_Remote, this.p_Variables), progressevent);
                return (this.m_Data != null);
            }
            else if (installation.Mode == Installation.InstallMode.UPDATE)
            {
                this.m_Data = Downloader.Grab(PathTranslator.Parse(this.p_Remote, this.p_Variables), progressevent);
                return (this.m_Data != null);
            }
            return true;
        }

        internal override bool DownloadRequired(Installation installation)
        {
            if (this.p_Generated || this.DeleteOnNextUpdate)
                return false;

            return (installation.Mode == Installation.InstallMode.INSTALL || 
                (installation.Mode == Installation.InstallMode.UPDATE && this.InstalledVersion < this.AvailableVersion));
        }

        internal override bool Install(Installation installation)
        {
            if (this.p_Generated)
                return true;

            if (this.m_Data == null)
                return false;

            // Write the file to disk.
            try
            {
                using (FileStream stream = new FileStream(PathTranslator.Parse(this.p_Local, this.p_Variables), FileMode.Create))
                {
                    using (BinaryWriter writer = new BinaryWriter(stream))
                    {
                        writer.Write(this.m_Data);
                        writer.Close();
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        internal override bool Update(Installation installation)
        {
            return this.Update(installation, false);
        }

        internal bool Update(Installation installation, bool temp)
        {
            // Handle deletion.
            if (this.DeleteOnNextUpdate)
            {
                return this.Uninstall(installation);
            }

            if (this.InstalledVersion == this.AvailableVersion)
                return true;

            if (this.p_Generated)
                return true;

            if (this.m_Data == null)
                return false;

            // Write the file to disk.
            try
            {
                using (FileStream stream = new FileStream(PathTranslator.Parse(this.p_Local, this.p_Variables), FileMode.Create))
                {
                    using (BinaryWriter writer = new BinaryWriter(stream))
                    {
                        writer.Write(this.m_Data);
                        writer.Close();
                    }
                }

                return true;
            }
            catch (IOException ex)
            {
                if (ex.Message.StartsWith("The process cannot access the file") && temp)
                {
                    // We are permitted to save this as a temporary file.
                    try
                    {
                        using (FileStream stream = new FileStream(PathTranslator.Parse(this.p_Local, this.p_Variables) + ".new", FileMode.Create))
                        {
                            using (BinaryWriter writer = new BinaryWriter(stream))
                            {
                                writer.Write(this.m_Data);
                                writer.Close();
                            }
                        }

                        return true;
                    }
                    catch (Exception ex2)
                    {
                        return false;
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        internal override bool Uninstall(Installation installation)
        {
            // Delete the file from disk.
            try
            {
                System.IO.File.Delete(PathTranslator.Parse(this.p_Local, this.p_Variables));
                return true;
            }
            catch (FileNotFoundException)
            {
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
